From: Ross Lagerwall Date: Wed, 27 Apr 2016 15:30:25 +0000 (-0400) Subject: x86, xsplice: Print payload's symbol name and payload name in backtraces X-Git-Tag: archive/raspbian/4.8.0-1+rpi1~1^2~1195 X-Git-Url: https://dgit.raspbian.org/%22http:/www.example.com/cgi/%22https:/%22bookmarks://%22Dat/%22http:/www.example.com/cgi/%22https:/%22bookmarks:/%22Dat?a=commitdiff_plain;h=d5ccf4482e4f3c99f1bcae242ce67bdd51f52537;p=xen.git x86, xsplice: Print payload's symbol name and payload name in backtraces Naturally the backtrace is presented when an instruction hits an bug_frame or %p is used. The payloads do not support bug_frames yet - however the functions the payloads call could hit an BUG() or WARN(). The traps.c has logic to scan for it this - and eventually it will find the correct bug_frame and the walk the stack using %p to print the backtrace. For %p and symbols to print a string - the 'is_active_kernel_text' is consulted which uses an 'struct virtual_region'. Therefore we register our start->end addresses so that 'is_active_kernel_text' will include our payload address. We also register our symbol lookup table function so that it can scan the list of payloads and retrieve the correct name. Lastly we change vsprintf to take into account s and namebuf. For core code they are the same, but for payloads they are different. This gets us: Xen call trace: [] revert_hook+0x31/0x35 [xen_hello_world] [] xsplice.c#revert_payload+0x86/0xc6 [] check_for_xsplice_work+0x233/0x3cd [] domain.c#continue_idle_domain+0x9/0x1f Which is great if payloads have similar or same symbol names. Signed-off-by: Ross Lagerwall Signed-off-by: Konrad Rzeszutek Wilk Reviewed-by: Andrew Cooper Reviewed-by: Jan Beulich Release-acked-by: Wei Liu --- diff --git a/xen/common/vsprintf.c b/xen/common/vsprintf.c index 18d2634693..70e1edf562 100644 --- a/xen/common/vsprintf.c +++ b/xen/common/vsprintf.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -354,6 +355,17 @@ static char *pointer(char *str, char *end, const char **fmt_ptr, str = number(str, end, sym_size, 16, -1, -1, SPECIAL); } + /* + * namebuf contents and s for core hypervisor are same but for xSplice + * payloads they differ (namebuf contains the name of the payload). + */ + if ( namebuf != s ) + { + str = string(str, end, " [", -1, -1, 0); + str = string(str, end, namebuf, -1, -1, 0); + str = string(str, end, "]", -1, -1, 0); + } + return str; } diff --git a/xen/common/xsplice.c b/xen/common/xsplice.c index 3d56c04946..e7872c62a1 100644 --- a/xen/common/xsplice.c +++ b/xen/common/xsplice.c @@ -14,7 +14,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -31,10 +33,9 @@ static LIST_HEAD(payload_list); /* * Patches which have been applied. Need RCU in case we crash (and then - * traps code would iterate via applied_list) when adding entries on the list. - * - * Note: There are no 'rcu_applied_lock' as we don't iterate yet the list. + * traps code would iterate via applied_list) when adding entries onthe list. */ +static DEFINE_RCU_READ_LOCK(rcu_applied_lock); static LIST_HEAD(applied_list); static unsigned int payload_cnt; @@ -56,6 +57,8 @@ struct payload { unsigned int nfuncs; /* Nr of functions to patch. */ const struct xsplice_symbol *symtab; /* All symbols. */ const char *strtab; /* Pointer to .strtab. */ + struct virtual_region region; /* symbol, bug.frame patching and + exception table (x86). */ unsigned int nsyms; /* Nr of entries in .strtab and symbols. */ char name[XEN_XSPLICE_NAME_SIZE]; /* Name of it. */ }; @@ -139,6 +142,55 @@ unsigned long xsplice_symbols_lookup_by_name(const char *symname) return 0; } +static const char *xsplice_symbols_lookup(unsigned long addr, + unsigned long *symbolsize, + unsigned long *offset, + char *namebuf) +{ + const struct payload *data; + unsigned int i, best; + const void *va = (const void *)addr; + const char *n = NULL; + + /* + * Only RCU locking since this list is only ever changed during apply + * or revert context. And in case it dies there we need an safe list. + */ + rcu_read_lock(&rcu_applied_lock); + list_for_each_entry_rcu ( data, &applied_list, applied_list ) + { + if ( va < data->text_addr || + va >= (data->text_addr + data->text_size) ) + continue; + + best = UINT_MAX; + + for ( i = 0; i < data->nsyms; i++ ) + { + if ( data->symtab[i].value <= addr && + (best == UINT_MAX || + data->symtab[best].value < data->symtab[i].value) ) + best = i; + } + + if ( best == UINT_MAX ) + break; + + if ( symbolsize ) + *symbolsize = data->symtab[best].size; + if ( offset ) + *offset = addr - data->symtab[best].value; + if ( namebuf ) + strlcpy(namebuf, data->name, KSYM_NAME_LEN); + + n = data->symtab[best].name; + break; + } + rcu_read_unlock(&rcu_applied_lock); + + return n; +} + static struct payload *find_payload(const char *name) { struct payload *data, *found = NULL; @@ -364,6 +416,7 @@ static int prepare_payload(struct payload *payload, const struct xsplice_elf_sec *sec; unsigned int i; struct xsplice_patch_func *f; + struct virtual_region *region; sec = xsplice_elf_sec_by_name(elf, ELF_XSPLICE_FUNC); ASSERT(sec); @@ -420,6 +473,13 @@ static int prepare_payload(struct payload *payload, } } + /* Setup the virtual region with proper data. */ + region = &payload->region; + + region->symbols_lookup = xsplice_symbols_lookup; + region->start = payload->text_addr; + region->end = payload->text_addr + payload->text_size; + return 0; } @@ -496,6 +556,7 @@ static int build_symbol_table(struct payload *payload, if ( is_payload_symbol(elf, elf->sym + i) ) { symtab[nsyms].name = strtab + strtab_len; + symtab[nsyms].size = elf->sym[i].sym->st_size; symtab[nsyms].value = elf->sym[i].sym->st_value; symtab[nsyms].new_symbol = 0; /* May be overwritten below. */ strtab_len += strlcpy(strtab + strtab_len, elf->sym[i].name, @@ -779,6 +840,7 @@ static int apply_payload(struct payload *data) * The applied_list is iterated by the trap code. */ list_add_tail_rcu(&data->applied_list, &applied_list); + register_virtual_region(&data->region); return 0; } @@ -801,6 +863,7 @@ static int revert_payload(struct payload *data) * The applied_list is iterated by the trap code. */ list_del_rcu(&data->applied_list); + unregister_virtual_region(&data->region); return 0; } diff --git a/xen/include/xen/xsplice.h b/xen/include/xen/xsplice.h index 0a6020df6a..331c383926 100644 --- a/xen/include/xen/xsplice.h +++ b/xen/include/xen/xsplice.h @@ -22,6 +22,7 @@ struct xen_sysctl_xsplice_op; struct xsplice_symbol { const char *name; unsigned long value; + unsigned int size; bool_t new_symbol; };